Skip to content

Refactor: Phase 1 shared 레이어 + Phase 2 entities 레이어 구축#2

Merged
mayrang merged 3 commits intomainfrom
refactor/phase-1-shared-layer
Mar 21, 2026
Merged

Refactor: Phase 1 shared 레이어 + Phase 2 entities 레이어 구축#2
mayrang merged 3 commits intomainfrom
refactor/phase-1-shared-layer

Conversation

@mayrang
Copy link
Copy Markdown
Owner

@mayrang mayrang commented Mar 21, 2026

Summary

FSD(Feature-Sliced Design) 리팩토링 Phase 1 ~ Phase 2 완료.

Phase 1: shared 레이어 구축

  • components/designSystem/shared/ui/ 이전 (31개 컴포넌트)
  • Emotion CSS-in-JS → Tailwind CSS 전환
  • 중복 코드 제거: ButtonContainer 3중복, DarkWrapper 3중복, BaseToast/BaseModal 추출
  • 버그 수정 7건 (height 단위 누락, display:flex 2중 선언 등)

Phase 1.5: 웹 접근성 보강

  • ARIA 패턴 적용: Select(combobox), BaseModal(dialog + focus trap + Escape)
  • jest-axe 도입, WCAG 위반 수정

Phase 1 잔여물 정리

  • shared/ui/icons/ 생성 → cross-layer 의존성 10개 해소
  • shared/ui/index.ts 생성 → barrel export 구성
  • jest-axe 전체 적용 (25개 파일) → WCAG 위반 13개 추가 발견·수정

Phase 2: entities 레이어 구축

  • shared/api/ 구성 (axiosInstance, handleApiResponse) — console.log 9개 제거
  • shared/types/ 구성 (RequestErrorType)
  • model/ + api/entities/{domain}/ 이전 (16개 도메인)
  • 레이어 위반 해소: Filters, IListParams 타입을 entities로 이전
  • 기존 import 경로 전부 re-export로 유지 (하위 호환)

Test plan

  • npx vitest run → 27 files, 159 tests 전부 통과 확인
  • 기존 페이지 동작 확인 (re-export로 인해 기존 import 경로 모두 유지됨)

수치

지표 Before After
테스트 0개 159개
FSD 준수 컴포넌트 0개 34개 (shared/ui) + 48개 (entities)
console.log 위반 9개 0개
cross-layer 의존성 12개 0개

🤖 Generated with Claude Code

## Phase 1 잔여물 정리
- shared/ui/icons/ 생성 (10개) — cross-layer deps 해소 (@/components/icons/ → @/shared/ui/icons/)
- shared/ui/index.ts 생성 — barrel export (import { Button } from '@/shared/ui' 가능)
- jest-axe 전체 적용 (25개 파일) — WCAG 위반 13개 발견 및 수정
  - Select nested-interactive 제거, CommentInput 버튼 aria-label, TextareaField tabIndex
  - CheckingModal/NoticeModal/ResultModal labelId 연결
  - BottomSheetModal aria-label prop 지원

## shared/api 구성
- shared/api/axiosInstance.ts — axios 인스턴스 + token refresh interceptor
- shared/api/handleApiResponse.ts — ApiResponse 인터페이스 + 응답 처리
- console.log 9개 제거 (CLAUDE.md 규칙)
- src/api/index.ts → re-export 래퍼로 교체 (17개 도메인 파일 변경 없음)

## shared/types 구성
- shared/types/error.ts — RequestErrorType
- src/model/error.ts → re-export 래퍼로 교체

## entities 레이어 구축 (16개 도메인)
- contact, notification, bookmark, report, translation, requestedTrip
- enrollment, comment, myTrip, search
- user (auth.ts + profile.ts 통합), userProfile, trip (home.ts 병합)
- tripDetail, community, myPage
- 각 domain: model.ts + api.ts + index.ts
- src/model/*.ts, src/api/*.ts → re-export 래퍼로 교체 (하위 호환)

## 레이어 위반 해소
- Filters 타입: hooks/search/useSearch → entities/search/model
- IListParams 타입: hooks/useCommunity → entities/community/model

테스트: 134개 → 159개 (전부 통과)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
release-back Ready Ready Preview, Comment Mar 21, 2026 10:37am
release-test Ready Ready Preview, Comment Mar 21, 2026 10:37am

@mayrang
Copy link
Copy Markdown
Owner Author

mayrang commented Mar 21, 2026

코드 리뷰 — Phase 1 잔여물 정리 + Phase 2 entities 레이어 구축

Claude Code (Pro) 로컬 리뷰 | 2026-03-21


✅ 잘 된 점

re-export 하위 호환 전략
src/api/index.ts@/shared/api re-export 패턴으로 17개 도메인 파일을 한 줄도 건드리지 않고 axiosInstance를 FSD 안으로 이전했다. 대규모 리팩토링에서 점진적 이전의 교과서적 예시.

레이어 위반 선제 해소
Filters (hooks → entities/search), IListParams (hooks → entities/community) 두 타입을 발견하고 즉시 이전 + re-export 처리. entities가 hooks를 import하는 구조였다면 Phase 3에서 순환 참조 가능성이 있었다.

불필요 import 정리
bookmark/api.ts에서 사용하지 않던 ITripList, daysAgo, dayjs, authStore 4개를 제거. 원본 코드의 기술 부채를 이전 과정에서 함께 해소.


⚠️ 개선 필요 사항

[중요] retryCount가 모듈 전역 변수 — 요청 간 상태 공유

// src/shared/api/axiosInstance.ts:17
let retryCount = 0; // ← 모듈 레벨 전역 변수

현재 retryCount가 모듈 레벨에 선언되어 있어 모든 API 요청이 카운터를 공유한다. 예를 들어 요청 A가 401을 3번 받고, 이후 요청 B가 401을 받으면 이미 카운터가 3인 상태로 시작한다. 리셋 로직도 없다.

원본 코드부터 있던 버그이므로 Phase 2 범위는 아니지만, Phase 3 auth feature 작업 시 수정 필요.

// 권장 방향 (Phase 3에서):
// originalRequest에 _retryCount를 붙여 요청별로 추적
async (error) => {
  const originalRequest = error.config;
  originalRequest._retryCount = (originalRequest._retryCount ?? 0) + 1;
  if (originalRequest._retryCount > MAX_RETRY_COUNT) { ... }
}

[중요] getHomeUserProfile — 잘못된 파라미터 사용

// src/entities/trip/api.ts:58
export const getHomeUserProfile = async (accessToken: string) => {
  const response = await axiosInstance.get(`/api/profile/me?userNumber=${accessToken}`);
  //                                                        ^^^^^^^^^^^^^^^^^^^^^^^^
  //                                          accessToken을 userNumber로 쿼리스트링에 전달 (버그)
};

accessTokenuserNumber 쿼리 파라미터로 전달하는 것은 명백한 버그. 원본 코드(api/home.ts)부터 있던 문제이며, 함수명도 getHomeUserProfile이어서 myPage/getMyPage와 역할이 겹친다. Phase 3에서 auth feature 작업 시 제거 or 수정 검토 필요.


[경미] entities/user/api.ts — 에러 처리 불일치

같은 파일 내에서 에러 처리 방식이 혼재한다.

// getUserTravelLog: RequestError throw (일관성 있음)
} catch (err: any) {
  throw new RequestError(err);
}

// getUser: console.error만 하고 undefined 반환 (불일관)
} catch (error: any) {
  console.error(error);
  // throw 없음 → 호출부에서 null/undefined 처리 필요
}

// kakaoLogin, googleLogin, naverLogin: console.error만 (불일관)

원본 코드의 패턴을 유지한 것이지만 Phase 3 auth feature 작업 시 RequestError throw로 통일 권장.


[경미] tripDetail/api.ts — entities 간 직접 import

// src/entities/tripDetail/api.ts:4
import { UpdateTripReqData } from '@/entities/trip';

FSD 공식 가이드에서는 같은 레이어(entities) 내 교차 import를 금지한다. UpdateTripReqDatatripDetail이 아닌 trip entity에 속해 있어 현재 이 구조가 불가피하지만, Phase 3에서 두 가지 해결책을 고려:

  1. UpdateTripReqDatashared/types/로 올려 공유
  2. tripDetail의 update 기능을 trip entity로 통합

[경미] shared/ui/index.tsexport * 이름 충돌 잠재 위험

export * from './button';
export * from './input';
// ...

현재는 문제없지만, 향후 카테고리 간 동일한 이름이 생기면 export * 충돌로 빌드 에러가 발생한다. 규모가 커지면 named re-export 방식도 고려.


📊 수치 요약

항목 Before After
FSD 준수 파일 0개 82개 (shared/ui 34 + entities 48)
console.log 위반 9개 0개
크로스 레이어 의존성 12개 0개
테스트 134개 159개

🎯 Phase 3 전 처리 권장 항목

우선순위 항목 위치
높음 retryCount 전역 변수 → 요청별 추적으로 수정 shared/api/axiosInstance.ts
높음 getHomeUserProfile 버그 수정 or 제거 entities/trip/api.ts
낮음 entities/user/api.ts 에러 처리 통일 Phase 3 auth feature
낮음 tripDetail → trip 교차 import 해소 Phase 3 trip-detail feature

- code-review.yml: pull_request 트리거 → workflow_dispatch only (API 크레딧 필요)
- CLAUDE.md: Claude Code CLI(Pro) + gh pr comment 수동 리뷰 절차 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mayrang mayrang merged commit 05f7bb1 into main Mar 21, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant